/* * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.grandcentrix.tray.sample.slice;

import net.grandcentrix.tray.AppPreferences;
import net.grandcentrix.tray.TrayPreferences;
import net.grandcentrix.tray.core.OnTrayPreferenceChangeListener;
import net.grandcentrix.tray.core.SharedPreferencesImport;
import net.grandcentrix.tray.core.TrayItem;
import net.grandcentrix.tray.core.TrayStorage;
import net.grandcentrix.tray.sample.ImportTrayPreferences;
import net.grandcentrix.tray.sample.MultiProcessService;
import net.grandcentrix.tray.sample.ResourceTable;
import net.grandcentrix.tray.util.LogUtil;
import net.grandcentrix.tray.util.PreferencesHelper;
import net.grandcentrix.tray.util.SqlcipherDbHelper;
import net.sqlcipher.database.SQLiteDatabase;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.IAbilityConnection;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.Text;
import ohos.agp.components.Button;
import ohos.agp.components.LayoutScatter;
import ohos.agp.window.dialog.ToastDialog;
import ohos.bundle.ElementName;
import ohos.data.preferences.Preferences;
import ohos.rpc.IRemoteObject;

import java.util.Collection;
import java.util.List;
import java.util.ArrayList;
import java.util.UUID;
import java.util.Iterator;

import static net.grandcentrix.tray.sample.MultiProcessService.INTENT_MODE_READ;
import static net.grandcentrix.tray.sample.MultiProcessService.INTENT_MODE_WRITE;

public class MainAbilitySlice extends AbilitySlice implements Component.ClickedListener {
    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "/data/user/0/net.grandcentrix.tray.sample/databases/tray.db";

    private static final String TAG = MainAbilitySlice.class.getSimpleName();

    private static final String STARTUP_COUNT = "startup_count";
    public static final String SHARED_PREF_NAME = "shared_pref";
    private static final String SHARED_PREF_KEY = "shared_pref_key";
    private static final String TRAY_PREF_KEY = "importedData";

    private static final int REQUEST_CODE = 0;

    private PreferencesHelper preferencesHelper;
    private AppPreferences mAppPrefs;
    private ImportTrayPreferences mImportPreference;

    private int mMultiProcessCounter = 0;

    private Text sharedPrefText;

    private OnTrayPreferenceChangeListener mAppPrefsListener
            = new OnTrayPreferenceChangeListener() {
        @Override
        public void onTrayPreferenceChanged(final Collection<TrayItem> items) {
            LogUtil.debug(TAG, "read in main process: changed " + getNiceString(items));
        }
    };

    private final OnTrayPreferenceChangeListener mImportPrefsListener
            = new OnTrayPreferenceChangeListener() {
        @Override
        public void onTrayPreferenceChanged(final Collection<TrayItem> items) {
            LogUtil.debug(TAG, "trayPrefs changed items: " + getNiceString(items));
            updateSharedPrefInfo();
        }
    };

    @SuppressWarnings("CommitPrefEdits")
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);

        // Load sqlcipher and initialize db name and version
        SQLiteDatabase.loadLibs(this);
        SqlcipherDbHelper.setDbVerName(DATABASE_VERSION, DATABASE_NAME);

        ComponentContainer rootLayout = (ComponentContainer) LayoutScatter.getInstance(this)
                .parse(ResourceTable.Layout_main_ability, null, false);

        sharedPrefText = (Text) rootLayout.findComponentById(ResourceTable.Id_shared_pref_info);

        Text counterText = (Text) rootLayout.findComponentById(ResourceTable.Id_counterText);

        final Button resetButton = (Button) rootLayout.findComponentById(ResourceTable.Id_resetButton);
        resetButton.setClickedListener(this);

        final Button writeSharedButton = (Button) rootLayout.findComponentById(ResourceTable.Id_write_shared_pref);
        writeSharedButton.setClickedListener(this);

        final Button importSharedButton = (Button) rootLayout.findComponentById(ResourceTable.Id_import_shared_pref);
        importSharedButton.setClickedListener(this);

        final Button multiprocessIncreaser = (Button) rootLayout.findComponentById(ResourceTable.Id_increase_multiprocess_counter);
        multiprocessIncreaser.setClickedListener(this);

        final Button multiprocessIncreaserOther = (Button) rootLayout.findComponentById(ResourceTable.Id_increase_multiprocess_counter_other_process);
        multiprocessIncreaserOther.setClickedListener(this);

        setUIContent(rootLayout);

        mAppPrefs = new AppPreferences(this);
        preferencesHelper = PreferencesHelper.getInstance();
        preferencesHelper.init(this, SHARED_PREF_NAME);
        int counter = preferencesHelper.getInt(STARTUP_COUNT);

        if(counter == 0) {
            preferencesHelper.putString("userToken", UUID.randomUUID().toString());
            preferencesHelper.putString("gcmToken", UUID.randomUUID().toString());
        }

        preferencesHelper.putInt(STARTUP_COUNT, ++counter);
        counterText.setText(String.valueOf(counter));

        testAutoBackup();

        mImportPreference = new ImportTrayPreferences(this);

        updateSharedPrefInfo();
    }

    @Override
    public void onActive() {
        super.onActive();

        updateSharedPrefInfo();

        preferencesHelper.registerObserver(mSharedPrefsListener);
        // implement observer change
//        mImportPreference.registerOnTrayPreferenceChangeListener(mImportPrefsListener);
//        mAppPrefs.registerOnTrayPreferenceChangeListener(mAppPrefsListener);
    }

    private void writeInSharedPref() {
        final String data = "SOM3 D4T4 " + (System.currentTimeMillis() % 100000);
        preferencesHelper.putString(SHARED_PREF_KEY, data);
    }

    @Override
    protected void onStop() {
        super.onStop();

        preferencesHelper.unregisterObserver(mSharedPrefsListener);
        mImportPreference.unregisterOnTrayPreferenceChangeListener(mImportPrefsListener);
        mAppPrefs.unregisterOnTrayPreferenceChangeListener(mAppPrefsListener);

    }

    private final Preferences.PreferencesObserver mSharedPrefsListener = new Preferences.PreferencesObserver() {
        @Override
        public void onChange(final Preferences sharedPreferences, final String key) {
            Object value = null;
            try {
                value = preferencesHelper.getString(key);
            } catch (ClassCastException e) {
            }
            try {
                value = preferencesHelper.getInt(key);
            } catch (ClassCastException e) {
            }
            LogUtil.debug(TAG, "sharedPrefs changed key: '" + key + "' value '" + value + "'");
            updateSharedPrefInfo();
        }
    };

    @Override
    public void onClick(Component component) {
        switch (component.getId()) {
            case ResourceTable.Id_resetButton:
                resetAndRestart();
                break;
            case ResourceTable.Id_write_shared_pref:
                writeInSharedPref();
                break;
            case ResourceTable.Id_import_shared_pref:
                importSharedPref();
                break;
            case  ResourceTable.Id_increase_multiprocess_counter:
                increaseMultiprocessCounter();
                break;
            case  ResourceTable.Id_increase_multiprocess_counter_other_process:
                increaseMultiprocessCounterInOtherProcess();
                break;
            default:
                ToastDialog toast = new ToastDialog(this);
                toast.setText("not implemented");
                toast.setDuration(1000);
                toast.show();
                break;
        }
    }

    private void testAutoBackup() {
        {
            // device specific data
            final TrayPreferences deviceSpecificPref =
                    new TrayPreferences(this, "nobackup", 1, TrayStorage.Type.DEVICE);
            final String deviceId = deviceSpecificPref.getString("deviceId", null);
            LogUtil.info(TAG, "deviceId: " + deviceId);
            if (deviceId == null) {
                final String uuid = UUID.randomUUID().toString();
                deviceSpecificPref.put("deviceId", uuid);
                LogUtil.info(TAG, "no deviceId, created: " + uuid);
            }
        }

        {
            // user specific data
            final TrayPreferences userSpecificPref =
                    new TrayPreferences(this, "autobackup", 1, TrayStorage.Type.USER);
            final String userId = userSpecificPref.getString("userId", null);
            LogUtil.info(TAG, "userId: " + userId);
            if (userId == null) {
                final String uuid = UUID.randomUUID().toString();
                userSpecificPref.put("userId", uuid);
                LogUtil.info(TAG, "no userId, created: " + uuid);
            }
        }
    }

    private void updateSharedPrefInfo() {
        final String sharedPrefData = preferencesHelper.getString(SHARED_PREF_KEY);
        final String trayData = mImportPreference.getString(TRAY_PREF_KEY, "null");

        sharedPrefText.setText("SharedPref Data: " + sharedPrefData + " Tray Data: " + trayData);
        LogUtil.debug(TAG, "Entering SharedPref Data: " + sharedPrefData + " Tray Data: " + trayData);
    }

    /**
     * write here read remote
     * <p>
     * check logcat to see the what happens
     */
    @SuppressWarnings("CommitPrefEdits")
    private void increaseMultiprocessCounter() {
        mMultiProcessCounter++;
        LogUtil.debug(TAG, "Entering write in main process: counter = " + mMultiProcessCounter);
        preferencesHelper.putInt(MultiProcessService.KEY_MULTIPROCESS_COUNTER_SERVICE_READ, mMultiProcessCounter);
        mAppPrefs.put(MultiProcessService.KEY_MULTIPROCESS_COUNTER_SERVICE_READ, mMultiProcessCounter);

        // starting a service in another process to read the values there.

        Intent intent = new Intent();
        Operation operation = new Intent.OperationBuilder().withDeviceId("")
                .withBundleName("net.grandcentrix.tray.sample")
                .withAbilityName("net.grandcentrix.tray.sample.MultiProcessService")
                .withAction(INTENT_MODE_WRITE)
                .build();
        intent.setOperation(operation);
        connectAbility(intent, randomConnection);
    }

    /**
     * write remote, get notified here with the listeners
     * <p>
     * check logcat to see what happens
     */
    private void increaseMultiprocessCounterInOtherProcess() {
        // the listeners will react to those changes. At least the tray listener because the
        // listener of the shared preferences has no idea something has changed in the shared prefs
        // in another process

        Intent intent = new Intent();
        Operation operation = new Intent.OperationBuilder().withDeviceId("")
                .withBundleName("net.grandcentrix.tray.sample")
                .withAbilityName("net.grandcentrix.tray.sample.MultiProcessService")
                .withAction(INTENT_MODE_READ)
                .build();
        intent.setOperation(operation);
        connectAbility(intent, randomConnection);
    }

    private void resetAndRestart() {
        mAppPrefs.remove(STARTUP_COUNT);
        preferencesHelper.putInt(STARTUP_COUNT, 0);
        //restart activity
        Intent intent = new Intent();
        intent.setElement(getContext().getElementName());
        intent.setFlags(Intent.FLAG_ABILITY_NEW_MISSION | Intent.FLAG_ABILITY_CLEAR_MISSION);
        startAbility(intent, REQUEST_CODE);
    }

    private void importSharedPref() {
        final SharedPreferencesImport sharedPreferencesImport =
                new SharedPreferencesImport(this, SHARED_PREF_NAME, SHARED_PREF_KEY, TRAY_PREF_KEY);
        mImportPreference.migrate(sharedPreferencesImport);
    }

    private List<String> getNiceString(final Collection<TrayItem> items) {
        List<String> list = new ArrayList<>();

        for (Iterator<TrayItem> iterator = items.iterator(); iterator.hasNext();) {
            TrayItem trayItem = iterator.next();
            list.add("key: '" + trayItem.key() + "' value '" + trayItem.value() + "'");
        }
        return list;
    }

    static IAbilityConnection randomConnection = new IAbilityConnection(){

        @Override
        public void onAbilityConnectDone(ElementName elementName, IRemoteObject iRemoteObject, int i) {
            LogUtil.info(TAG, "onAbilityConnectDon");
        }

        @Override
        public void onAbilityDisconnectDone(ElementName elementName, int i) {
            LogUtil.info(TAG, "onAbilityDisconnectDone");
        }
    };
}